package com.ctsi.offlinesupport.service;

import com.ctsi.commons.util.UtilValidate;
import com.ctsi.framework.mybatis.support.MybatisGenericDao;
import com.ctsi.supportflow.app.entity.SupportTask;
import org.flowable.bpmn.model.Activity;
import org.flowable.bpmn.model.FlowNode;
import org.flowable.bpmn.model.SequenceFlow;
import org.flowable.common.engine.impl.identity.Authentication;
import org.flowable.engine.*;
import org.flowable.engine.history.HistoricActivityInstance;
import org.flowable.engine.history.HistoricProcessInstance;
import org.flowable.engine.impl.bpmn.behavior.BoundaryEventActivityBehavior;
import org.flowable.engine.impl.bpmn.behavior.GatewayActivityBehavior;
import org.flowable.engine.impl.bpmn.behavior.MultiInstanceActivityBehavior;
import org.flowable.engine.impl.bpmn.behavior.TaskActivityBehavior;
import org.flowable.engine.impl.persistence.entity.ExecutionEntity;
import org.flowable.engine.impl.persistence.entity.ExecutionEntityManager;
import org.flowable.engine.impl.util.CommandContextUtil;
import org.flowable.engine.impl.util.ProcessDefinitionUtil;
import org.flowable.engine.runtime.Execution;
import org.flowable.task.api.history.HistoricTaskInstance;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.*;

/**
 * @author: zhangjw
 * @Date: 2018/11/24 14:30
 * @Description:
 */
@Service
public class FlowBackService {
    private static final Logger logger = LoggerFactory.getLogger(FlowBackService.class);
    private static Map<String, List<Activity>> processActivitiMap = new HashMap<>();
    @Autowired
    private RuntimeService runtimeService;
    @Autowired
    private TaskService taskService;
    @Autowired
    private HistoryService historyService;
    @Autowired
    private MybatisGenericDao dao;
    @Autowired
    private SupportTaskService supportTaskService;
    @Autowired
    private ManagementService managementService;
    @Autowired
    private RepositoryService repositoryService;

    public void sendBack(String taskId, String curUserId, String comment) {
        HistoricTaskInstance task = historyService.createHistoricTaskInstanceQuery().unfinished().taskId(taskId).singleResult();

        if (UtilValidate.isNotEmpty(comment)) {
            Authentication.setAuthenticatedUserId(curUserId);
            taskService.addComment(taskId, task.getProcessInstanceId(), "back", comment);
        }

        /**
         * 判断该环节是否是多实例环节
         */
        HistoricProcessInstance process = historyService.createHistoricProcessInstanceQuery().processInstanceId(task.getProcessInstanceId()).singleResult();
        /**
         * 判断本节点是否是多实例
         */
        Activity activity = (Activity) managementService.executeCommand(commandContext -> ProcessDefinitionUtil.getBpmnModel(process.getProcessDefinitionId()).getFlowElement(task.getTaskDefinitionKey()));
        if (activity.getBehavior() instanceof MultiInstanceActivityBehavior) {
            // 多实例环节需要维护状态
            SupportTask temp = new SupportTask();
            temp.setTaskStatus(1);
            temp.setTaskId(taskId);
            supportTaskService.updateSupportTaskByPKSelective(temp);

            Integer nrOfInstances = (Integer) taskService.getVariable(task.getId(), "nrOfInstances");
            Integer nrOfCompletedInstances = (Integer) taskService.getVariable(task.getId(),"nrOfCompletedInstances");
            logger.warn("{} number of Instances count is {}", task.getTaskDefinitionKey(), nrOfInstances);
            if (nrOfInstances > 1) {
                /**
                 * 减签
                 */
                Execution execution = runtimeService.createExecutionQuery().executionId(task.getExecutionId()).singleResult();
                String parentExecutionId = execution.getParentId();
                runtimeService.deleteMultiInstanceExecution(execution.getId(), true);
                if ((nrOfInstances - nrOfCompletedInstances) == 1 ) {
                    // 多实例最后一个环节，应该继续走向下一个环节
                    // 获取执行ID
                    managementService.executeCommand(commandContext -> {
                        ExecutionEntityManager executionEntityManager = CommandContextUtil.getExecutionEntityManager(commandContext);
                        ExecutionEntity rootExecution=  executionEntityManager.findById(parentExecutionId);
                        FlowableEngineAgenda agenda = CommandContextUtil.getAgenda(commandContext);
                        List<SequenceFlow> flows = activity.getOutgoingFlows();
                        for (SequenceFlow flow : flows) {
                            rootExecution.setCurrentFlowElement(flow);
                            agenda.planTakeOutgoingSequenceFlowsOperation(rootExecution,true);
                        }
                        return null;
                    });
                }
                return;
            }
        }
        // 获取上一环节
        HistoricActivityInstance instance = this.getPrevTaskByCurrentTaskId(task.getProcessInstanceId(), activity);
        if (instance == null) {
            this.delTask(task);
            return;
        }else{
            final String preActId = instance.getActivityId();
            Activity preActivity = (Activity) managementService.executeCommand(commandContext -> ProcessDefinitionUtil.getBpmnModel(process.getProcessDefinitionId()).getFlowElement(preActId));
            if (preActivity.getBehavior() instanceof MultiInstanceActivityBehavior) {
                throw new RuntimeException("上环节为多实例环节不允许退回!");
            } else {
                if (instance.getActivityId().equals("auto-service-task")) {
                    // 判断当前环节是否是政支主任派单，退回直接退给发单人
                    if (task.getTaskDefinitionKey().equals("city-send-activity") || task.getTaskDefinitionKey().equals("provincial-send-activity")) {
                        instance = this.getPrevTaskByCurrentTaskId(task.getProcessInstanceId(), preActivity);
                        this.back(task,instance);
                    } else if (task.getTaskDefinitionKey().equals("supporting")) {
                        // 当前环节是支撑环节，直接退到自动派单环节
                        this.back(task,instance);
                    } else {
                        this.back(task,instance);
                    }
                } else {
                    this.back(task,instance);
                }
            }
        }
    }


    // ------------------新的退回策略-----------------------

    /**
     * 非多实例环节，直接退回
     */
    private void back(HistoricTaskInstance src, HistoricActivityInstance dest) {
        logger.warn("from {} to {}", src.getTaskDefinitionKey(), dest);
        runtimeService.createChangeActivityStateBuilder()
                .processInstanceId(src.getProcessInstanceId())
                .moveActivityIdTo(src.getTaskDefinitionKey(), dest.getActivityId())
                .changeState();
    }

    /**
     * 对于不能退回的环节，直接删除,只能删除执行实例
     *
     * @param task
     */
    private void delTask(HistoricTaskInstance task) {
        logger.warn("delete task {} for back", task.getTaskDefinitionKey());
        ExecutionEntity execution = (ExecutionEntity) runtimeService.createExecutionQuery().processInstanceId(task.getProcessInstanceId()).activityId(task.getTaskDefinitionKey()).singleResult();
        managementService.executeCommand(commandContext -> {
            ExecutionEntityManager manager = CommandContextUtil.getExecutionEntityManager(commandContext);
//            manager.deleteChildExecutions(execution,"back",true);
            manager.deleteExecutionAndRelatedData(execution, "back");
            return null;
        });
    }

    /**
     * @param curActivity
     * @return
     */
    public Set<Activity> getDestActivitis(FlowNode curActivity) {
        List<SequenceFlow> flows = curActivity.getIncomingFlows();
        Set<Activity> srcs = new HashSet<>();
        for (SequenceFlow flow : flows) {
            /**
             * 此处可以肯定 返回类型肯定是flowNode类型
             */
            FlowNode node = (FlowNode) flow.getSourceFlowElement();
            logger.warn("src element is {},id is {}", node.getBehavior(), node.getId());
            if (node.getBehavior() instanceof TaskActivityBehavior) {
                //任务节点
                srcs.add((Activity) node);
            }
            if (node.getBehavior() instanceof GatewayActivityBehavior) {
                // 网关节点
                srcs.addAll(getDestActivitis(node));
            }
            if (node.getBehavior() instanceof BoundaryEventActivityBehavior) {
                // 边界事件节点
                break;
            }

        }
        return srcs;
    }


    public HistoricActivityInstance getPrevTaskByCurrentTaskId(String processInstanceId, Activity curActivity) {
        Set<Activity> prevTaskIds = getDestActivitis(curActivity);
        HistoricActivityInstance activityInstance = null;
        if (prevTaskIds != null && prevTaskIds.size() > 0) {
            //遍历当前节点的所有incoming节点。判断最新的节点是哪个
            for (Activity preact : prevTaskIds) {
                List<HistoricActivityInstance>  activityInstances = historyService.createHistoricActivityInstanceQuery()
                        .processInstanceId(processInstanceId)
                        .activityId(preact.getId())
                        .orderByHistoricActivityInstanceEndTime()
                        .desc()
                        .listPage(0, 1);
                if (UtilValidate.isEmpty(activityInstances)) {
                    continue;
                }
                if (activityInstance == null ) {
                    activityInstance = activityInstances.get(0);
                    continue;
                }
                Date endTime = activityInstances.get(0).getEndTime();
                if (activityInstance.getEndTime().before(endTime)) {
                    activityInstance = activityInstances.get(0);
                } else
                {
                    continue;
                }
            }
        }
        return activityInstance;
    }




}
